package com.rw.coco.reply.impl;

import com.rw.coco.api.data.model.CharacterPropertyModel;
import com.rw.coco.api.reply.mapper.DiceReply;
import com.rw.coco.expression.DiceExpression;
import com.rw.coco.handler.message.event.CocoGroupMessageEvent;
import com.rw.coco.handler.message.event.CocoMessageEvent;
import com.rw.coco.handler.message.reply.handler.command.assistant.ra.SuccessLevel;
import com.rw.coco.handler.message.reply.handler.command.bean.CocoProp;
import com.rw.coco.handler.message.reply.handler.command.bean.RAResult;
import com.rw.coco.handler.message.reply.handler.command.bean.RARule;
import com.rw.coco.reply.constants.DiceReplyKey;
import com.rw.coco.reply.impl.util.ExpressionExceptionUtil;
import com.rw.coco.reply.reader.CocoPropertiesReader;
import com.rw.coco.util.CocoStringUtil;
import com.rw.coco.util.config.MainPropName;
import com.rw.tool.util.expression.exception.ExpressionException;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 通常回复
 */
public class PropertiesDiceReply implements DiceReply {
    private final CocoPropertiesReader reader;

    public PropertiesDiceReply(CocoPropertiesReader reader) {
        this.reader = reader;
    }

    @Override
    public String numberOverflowException(CocoMessageEvent event) {
        return reader.get(DiceReplyKey.NUMBER_OVERFLOW);
    }

    @Override
    public String roll(CocoMessageEvent event, String reason, String expression) {
        String template = reader.get(DiceReplyKey.ROLL);
        String nick = event.getNick();
        return MessageFormat.format(template, nick, reason, expression);
    }

    @Override
    public String privateRollReply(CocoGroupMessageEvent event, String reason, String expression) {
        String template = reader.get(DiceReplyKey.PRIVATE_ROLL_REPLY);
        String nick = event.getNick();
        return MessageFormat.format(template, nick);
    }

    @Override
    public String privateRollResult(CocoGroupMessageEvent event, String reason, String expression) {
        String template = reader.get(DiceReplyKey.PRIVATE_ROLL_RESULT);
        String nick = event.getNick();
        String groupName = event.getGroup().getName();
        String groupId = event.getGroup().getId();
        return MessageFormat.format(template, nick, groupName, groupId, reason, expression);
    }

    @Override
    public String expressionException(ExpressionException exception) {
        return ExpressionExceptionUtil.exceptionToString(exception, reader);
    }

    @Override
    public String setPropError(CocoMessageEvent event, String errorPosition) {
        return MessageFormat.format(reader.get(DiceReplyKey.SET_PROP_ERROR), errorPosition);
    }

    @Override
    public String setPropSuccess(CocoMessageEvent event) {
        return MessageFormat.format(reader.get(DiceReplyKey.SET_PROP_SUCCESS), event.getNick());
    }

    @Override
    public String setPropEmpty(CocoMessageEvent event) {
        return reader.get(DiceReplyKey.SET_PROP_EMPTY);
    }

    @Override
    public String clearAllProp(CocoMessageEvent event) {
        return reader.get(DiceReplyKey.CLEAR_ALL_PROP);
    }

    @Override
    public String delete(CocoMessageEvent event, String propName) {
        return MessageFormat.format(reader.get(DiceReplyKey.DELETE), event.getNick(), propName);
    }

    @Override
    public String deleteButNotFound(CocoMessageEvent event, String propName) {
        return MessageFormat.format(reader.get(DiceReplyKey.DELETE_BUT_NOT_FOUND), propName);
    }

    @Override
    public String raEmpty(CocoMessageEvent event) {
        return reader.get(DiceReplyKey.RA_EMPTY);
    }

    @Override
    public String raNotFindProp(CocoMessageEvent event, String propName) {
        return MessageFormat.format(reader.get(DiceReplyKey.RA_NOT_FIND_PROP), propName);
    }

    @Override
    public String raCommandError(CocoMessageEvent event, String errorCommand, int index) {
        String errorHint = CocoStringUtil.openWindow(errorCommand, index, 4);
        return MessageFormat.format(reader.get(DiceReplyKey.RA_COMMAND_ERROR), errorHint);
    }

    @Override
    public String tooManyBonuses(CocoMessageEvent event, int count, int maxCount) {
        return MessageFormat.format(reader.get(DiceReplyKey.TOO_MANY_BONUSES), String.valueOf(count),
                String.valueOf(maxCount));
    }

    @Override
    public String tooManyCount(CocoMessageEvent event, int count, int maxCount) {
        return MessageFormat.format(reader.get(DiceReplyKey.TOO_MANY_COUNT), String.valueOf(count),
                String.valueOf(maxCount));
    }

    @Override
    public String propNumTooBig(CocoMessageEvent event, int num, int maxNum) {
        return MessageFormat.format(reader.get(DiceReplyKey.PROP_NUM_TOO_BIG), String.valueOf(num),
                String.valueOf(maxNum));
    }

    @Override
    public String raResult(CocoMessageEvent event, RARule raRule, List<RAResult> raResultList) {
        // 获取标题
        String raTitle = MessageFormat.format(reader.get(DiceReplyKey.RA_RESULT_TITLE), event.getNick(),
                raRule.getName());

        StringBuilder result = new StringBuilder(raTitle);
        for (RAResult raResult : raResultList) {
            // 获取成功提示
            String successHint = getSuccessHint(raResult.getSuccessLevel());
            // 生成回复
            String raLoopReply = getRALoopReply(raRule, raResult, successHint);

            // 如果检定次数只有一次，则不需要换行
            if (raResultList.size() > 1) {
                result.append("\n");
            }

            result.append(raLoopReply);
        }

        return result.toString();
    }

    /**
     * 根据成功等级返回成功提示
     */
    private String getSuccessHint(SuccessLevel successLevel) {
        switch (successLevel) {
            case FATAL:
                return reader.get(DiceReplyKey.RA_FATAL);
            case FAILURE:
                return reader.get(DiceReplyKey.RA_FAILURE);
            case REGULAR_SUCCESS:
                return reader.get(DiceReplyKey.RA_REGULAR_SUCCESS);
            case HARD_SUCCESS:
                return reader.get(DiceReplyKey.RA_HARD_SUCCESS);
            case EXTREME_SUCCESS:
                return reader.get(DiceReplyKey.RA_EXTREME_SUCCESS);
            case CRITICAL_SUCCESS:
                return reader.get(DiceReplyKey.RA_CRITICAL_SUCCESS);
            default:
                throw new IllegalArgumentException("unknown successLevel: " + successLevel);
        }
    }

    /**
     * 获得RA检定的循环回复
     */
    private String getRALoopReply(RARule raRule, RAResult raResult, String successHint) {
        // 奖励/惩罚骰子拼接字符串
        String bonusesStr = raResult.getBonusesDice()
                .stream()
                .map(Objects::toString)
                .collect(Collectors.joining(" "));

        // 根据是否拥有奖励骰子，进行分类讨论
        int bonusesDice = raRule.getBonusesDice();
        if (bonusesDice > 0) {
            return MessageFormat.format(reader.get(DiceReplyKey.RA_RESULT_LOOP_BONUSES), bonusesDice,
                    raResult.getRandomValue(), bonusesStr, raResult.getResult(), raRule.getValue(), successHint);
        } else if (bonusesDice < 0) {
            return MessageFormat.format(reader.get(DiceReplyKey.RA_RESULT_LOOP_PENALTIES), -bonusesDice,
                    raResult.getRandomValue(), bonusesStr, raResult.getResult(), raRule.getValue(), successHint);
        } else {
            return MessageFormat.format(reader.get(DiceReplyKey.RA_RESULT_LOOP), raResult.getRandomValue(),
                    raRule.getValue(), successHint);
        }
    }

    @Override
    public String privateRAReply(CocoGroupMessageEvent event, String propName) {
        return MessageFormat.format(reader.get(DiceReplyKey.PRIVATE_RA_REPLY), event.getNick(), propName);
    }

    @Override
    public String privateRAResult(CocoGroupMessageEvent event, String result) {
        return MessageFormat.format(reader.get(DiceReplyKey.PRIVATE_RA_RESULT), event.getNick(),
                event.getSender().getId(), event.getGroup().getName(), event.getGroup().getId(), result);
    }

    @Override
    public String setShowNotFindProp(CocoMessageEvent event, String propName) {
        return MessageFormat.format(reader.get(DiceReplyKey.SET_NOT_FIND_PROP), event.getNick(), propName);
    }

    @Override
    public String setShowOne(CocoMessageEvent event, CharacterPropertyModel model) {
        String name = model.getPropertiesName();
        Integer value = model.getPropertiesValue();
        return MessageFormat.format(reader.get(DiceReplyKey.SET_SHOW_ONE), event.getNick(), name, value.toString());
    }

    @Override
    public String setShowAll(CocoMessageEvent event, Set<CharacterPropertyModel> properties) {
        // 如果属性为空，则返回空
        if (properties.isEmpty()) {
            return MessageFormat.format(reader.get(DiceReplyKey.SET_SHOW_ALL_BUT_NONE), event.getNick());
        }

        MainPropName mainPropName = event.getCocoData().getCocoConfig().getMainPropName();
        List<CharacterPropertyModel> sort = new ArrayList<>();
        // 先把主要属性放入列表中
        for (String propName : mainPropName.sortProp) {
            properties.stream()
                    .filter(model -> propName.equalsIgnoreCase(model.getPropertiesName()))
                    .findAny()
                    .ifPresent(sort::add);
        }

        // 然后依次把剩余属性放入列表中
        properties.stream()
                .filter(property -> !mainPropName.sortProp.contains(property.getPropertiesName()))
                .forEach(sort::add);

        // 获取消息的标题部分
        String title = MessageFormat.format(reader.get(DiceReplyKey.SET_SHOW_ALL_TITLE), event.getNick());

        // 拼接消息的循环部分
        String body = sort.stream()
                .map(this::loopMsg)
                .collect(Collectors.joining(" "));

        // 展示
        return title + "\n" + body;
    }

    @Override
    public String setPropOutOfRange(CocoMessageEvent event, CocoProp cocoProp, int minValue, int maxValue) {
        return MessageFormat.format(reader.get(DiceReplyKey.SET_PROP_OUT_OF_RANGE),
                minValue, String.valueOf(maxValue), event.getNick(), cocoProp.getName(),
                String.valueOf(cocoProp.getValue()));
    }

    /**
     * 获取循环部分的一条消息
     */
    private String loopMsg(CharacterPropertyModel model) {
        String name = model.getPropertiesName();
        Integer value = model.getPropertiesValue();
        return MessageFormat.format(reader.get(DiceReplyKey.SET_SHOW_ALL_LOOP), name, value.toString());
    }

    @Override
    public String nnNotFound(CocoMessageEvent event) {
        return reader.get(DiceReplyKey.NN_NOT_FOUND);
    }

    @Override
    public String nnClear(CocoMessageEvent event) {
        return reader.get(DiceReplyKey.NN_CLEAR);
    }

    @Override
    public String nn(CocoMessageEvent event, String nick) {
        return MessageFormat.format(reader.get(DiceReplyKey.NN), nick);
    }

    @Override
    public String scParseError(CocoMessageEvent event, String scCommand) {
        return reader.get(DiceReplyKey.SC_PARSE_ERROR);
    }

    @Override
    public String scFail(CocoMessageEvent event, DiceExpression diceExpression, int san, int minus, int randomNum) {
        return null;
    }

    @Override
    public String scSuccess(CocoMessageEvent event, DiceExpression diceExpression, int san, int minus, int randomNum) {
        return null;
    }
}
